package com.junyidao.game.core.aop;

import com.alibaba.fastjson.JSON;
import com.junyidao.game.core.LoginInfo;
import com.junyidao.game.core.annotation.Action;
import com.junyidao.game.core.annotation.OperLog;
import com.junyidao.game.pojo.PLoginLog;
import com.junyidao.game.pojo.POperLog;
import com.junyidao.game.pojo.SysUser;
import com.junyidao.game.service.LoginLogService;
import com.junyidao.game.service.OperLogService;
import com.junyidao.game.service.SequenceService;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by HP on 2016/8/12.
 */
@Aspect
@Component
public class OperLogAspect {

    private static Logger log = LogManager.getLogger(OperLogAspect.class);

    @Autowired
    private OperLogService operLogService;

    @Autowired
    private LoginLogService loginLogService;

    @Pointcut("@annotation(com.junyidao.game.core.annotation.Action)")
    public void operLogAspect() {

    }

    @After("operLogAspect()")
    public void doAfterForRequest(JoinPoint joinPoint) {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            SysUser user = LoginInfo.getUser();
            Map<String, Object> map = getRequestDescription(joinPoint);
            String operType = (String) map.get("operType");
            String desc = (String) map.get("desc") + JSON.toJSONString(request.getParameterMap());
            boolean isLogin = (boolean) map.get("isLogin");
            boolean needLog = (boolean) map.get("needLog");
            if (isLogin) {
                PLoginLog log = new PLoginLog();
                log.setUid(user.getUid());
                log.setHappenTime(new Date());
                log.setLogContent(desc);
                log.setLogType(operType);
                log.setIpAddr(getIpAddr(request));
                loginLogService.addLoginLog(log);
            } else {
                if (needLog) {
                    POperLog log = new POperLog();
                    log.setUid(user.getUid());
                    log.setIpAddr(getIpAddr(request));
                    log.setLogComtent(desc);
                    log.setOperType(operType);
                    log.setOperTime(new Date());
                    operLogService.addOperLog(log);
                }
            }
        } catch (Exception e) {
//            e.printStackTrace();
            log.error(e.getStackTrace());
        }
    }


    /**
     * 获取注解中对方法的描述信息 用于LoginLog注解
     *
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception
     */
    public Map<String, Object> getRequestDescription(JoinPoint joinPoint) throws Exception {
        Map<String, Object> map = new HashMap<>();
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        //获取切点方法的参数
        Object[] arguments = joinPoint.getArgs();
        Class<?> targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String operType = "";
        String desc = "";
        boolean isLogin = false;
        boolean needLog = false;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class<?>[] clazzs = method.getParameterTypes();
                //判断方法的参数个数是否等于目标方法的参数个数
                if (clazzs.length == arguments.length) {
                    operType = method.getAnnotation(Action.class).operType();
                    desc = method.getAnnotation(Action.class).desc();
                    isLogin = method.getAnnotation(Action.class).isLogin();
                    needLog = method.getAnnotation(Action.class).needLog();
                    map.put("operType", operType);
                    map.put("desc", desc);
                    map.put("isLogin", isLogin);
                    map.put("needLog", needLog);
                    break;
                }
            }
        }
        return map;
    }

    public String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }


}
